home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Games / SoundSprocketTest / TS3Sound.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  19.0 KB  |  792 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    File:        TS3Sound.c
  3.  *
  4.  *    Contents:    Handles some of the sound stuff.
  5.  *
  6.  *    Copyright © 1996 Apple Computer, Inc.
  7.  */
  8.  
  9. #include <assert.h>
  10. #include <math.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13.  
  14. #include <Components.h>
  15. #include <Controls.h>
  16. #include <Dialogs.h>
  17. #include <Sound.h>
  18. #include <SoundComponents.h>
  19. #include <Resources.h>
  20. #include <Timer.h>
  21. #include <ToolUtils.h>
  22. #include <Types.h>
  23.  
  24. #define __USING_OLD_SOUND_H__ 0
  25. #include "SoundSprocket.h"
  26.  
  27. #include "TS3Message.h"
  28. #include "TS3Resource.h"
  29. #include "TS3Sound.h"
  30. #include "TS3Utils.h"
  31. #include "TS3Window.h"
  32.  
  33. static SndChannelPtr        gSoundChannel            = NULL;
  34. static SndListHandle        gSoundResource            = NULL;
  35. static DialogPtr            gSoundDialog            = NULL;
  36. static SSpLocalizationData    gSoundPrev3DInfo;
  37.  
  38.  
  39. static Boolean CheckVersionNumber(
  40.     const NumVersion*        inVersion,
  41.     UInt8                    inMajor,
  42.     UInt8                    inMinor,
  43.     UInt8                    inBug);
  44.  
  45. static WindowMethodPtr Sound_MetaHandler(
  46.     WindowMethod        inMethod);
  47.  
  48. static void Sound_ConsumeEvent(
  49.     WindowPtr            inWindow,
  50.     const EventRecord*    inEvent,
  51.     Boolean*            outConsumed);
  52.  
  53. static void Sound_Update(
  54.     WindowPtr            inWindow);
  55.  
  56. static Boolean EventProc(
  57.     EventRecord        *inEvent);
  58.  
  59. static pascal void Sound_BoxUserItem(
  60.     DialogPtr            inDialog,
  61.     short                inItem);
  62.  
  63.  
  64. /*******************************************************************************
  65.  *    CheckVersionNumber
  66.  *
  67.  *    Returns true if the given version number is compatible with (i. e not older
  68.  *    than) version inMajor.inMinor.inBug.
  69.  ******************************************************************************/
  70. Boolean CheckVersionNumber(
  71.     const NumVersion*        inVersion,
  72.     UInt8                    inMajor,
  73.     UInt8                    inMinor,
  74.     UInt8                    inBug)
  75. {
  76.     if (inVersion->majorRev != inMajor)
  77.     {
  78.         return inVersion->majorRev > inMajor;
  79.     }
  80.     else
  81.     {
  82.         return inVersion->minorAndBugRev >= inMinor << 4 | inBug;
  83.     }
  84. }
  85.  
  86.  
  87. // **************************** GetSSpFilterVersion ****************************
  88. // Finds the manufacturer and version number of the SoundSprocket filter that
  89. // may be installed.  inManufacturer should be the manufacturer code specified
  90. // at the installation time, which may be zero to allow any manufacturer.
  91. // If no error is encountered, outManufacturer is set to the actual manufacturer
  92. // code and outMajorVersion and outMinorVersion are set to the component
  93. // specification level and manufacturer's implementation revision, respectively.
  94. static OSStatus GetSSpFilterVersion(
  95.     OSType                    inManufacturer,
  96.     OSType*                    outManufacturer,
  97.     UInt32*                    outMajorVersion,
  98.     UInt32*                    outMinorVersion)
  99. {
  100.     OSStatus                err;
  101.     ComponentDescription    description;
  102.     Component                componentRef;
  103.     UInt32                    vers;
  104.     
  105.     // Set up the component description
  106.     description.componentType            = kSoundEffectsType;
  107.     description.componentSubType        = kSSpLocalizationSubType;
  108.     description.componentManufacturer    = inManufacturer;
  109.     description.componentFlags            = 0;        
  110.     description.componentFlagsMask        = 0;    
  111.     
  112.     // Find a component matching the description
  113.     componentRef = FindNextComponent(nil, &description);
  114.     if (componentRef == nil)  return couldntGetRequiredComponent;
  115.     
  116.     // Get the component description (for the manufacturer code)
  117.     err = GetComponentInfo(componentRef, &description, nil, nil, nil);
  118.     if (err != noErr)  return err;
  119.     
  120.     // Get the version composite
  121.     vers = (UInt32) GetComponentVersion((ComponentInstance) componentRef);
  122.     
  123.     // Return the results
  124.     *outManufacturer = description.componentManufacturer;
  125.     *outMajorVersion = HiWord(vers);
  126.     *outMinorVersion = LoWord(vers);
  127.     
  128.     return noErr;
  129. }
  130.  
  131.  
  132. /* =============================================================================
  133.  *        Sound_Init (external)
  134.  *
  135.  *    Initializes the sound stuff.
  136.  * ========================================================================== */
  137. void Sound_Init(
  138.     void)
  139. {
  140.     OSStatus            err;
  141.     SoundComponentLink    link;
  142.     NumVersion            version;
  143.     OSType                manufacturer;
  144.     UInt32                majorVersion;
  145.     UInt32                minorVersion;
  146.     
  147.     assert(kFeedbackItem_COUNT == kFeedbackItem_ExpectedCount);
  148.     
  149.     // Check the sound manager version
  150.     version = SndSoundManagerVersion();  //••• WARNING •••
  151.     //• IF YOU CAN'T COMPILE THE PREVIOUS LINE, YOU MUST UPGRADE TO ETO #20 OR
  152.     //• EDIT YOUR Sound.h TO MAKE SndSoundManagerVersion RETURN THE TYPE NumVersion.
  153.     
  154.     if (!CheckVersionNumber(&version, 3, 2, 1))
  155.     {
  156.         StopAlert(kAlrtID_SoundMgrVersion, NULL);
  157.         // Note: A normal application would bail on 3D sound here
  158.     }
  159.     
  160.     // Allocate the sound channel
  161.     err = SndNewChannel(&gSoundChannel, sampledSynth, initMono, NULL);
  162.     Message_CheckError(err, "Sound_Init", "SndNewChannel");
  163.     
  164.     assert(gSoundChannel != NULL);
  165.     
  166.     // Install the 3D sound filters
  167.     link.description.componentType            = kSoundEffectsType;
  168.     link.description.componentSubType        = kSSpLocalizationSubType;
  169.     link.description.componentManufacturer    = 0;
  170.     link.description.componentFlags            = 0;        
  171.     link.description.componentFlagsMask        = 0;    
  172.     link.mixerID                            = nil;
  173.     link.linkID                                = nil;
  174.     
  175.     SndSetInfo(gSoundChannel, siPreMixerSoundComponent, &link);
  176.     Message_CheckError(err, "Sound_Init", "SndNewChannel");
  177.     
  178.     // Verify that the right version filter was installed
  179.     err = GetSSpFilterVersion(
  180.             link.description.componentManufacturer,
  181.             &manufacturer,
  182.             &majorVersion,
  183.             &minorVersion);
  184.     
  185.     if (err != noErr)
  186.     {
  187.         // Filter must not be installed
  188.         // Note: A normal application would bail on 3D sound here
  189.         StopAlert(kAlrtID_FilterNotInstalled, NULL);
  190.     }
  191.     else
  192.     {
  193.         // The major version represents the component specification level
  194.         if (majorVersion < 1)
  195.         {
  196.             //• if we couldn't handle some old version, we could bail here.
  197.             
  198.             StopAlert(kAlrtID_FilterVersion, NULL);
  199.             // Note: A normal application would bail on 3D sound here
  200.         }
  201.         else
  202.         {
  203.             // The minor version specifies the manufacturer's implementation revision
  204.             
  205.             //• could do something here is we needed to handle tweaks for specific
  206.             //• manufacturers or versions.
  207.         }
  208.     }
  209.  
  210.     // Grab the dialog
  211.     gSoundDialog = GetNewDialog(kDlogID_Feedback, NULL, (WindowPtr) -1);
  212.     assert(gSoundDialog != NULL);
  213.     
  214.     // Set up our method table
  215.     Window_New(gSoundDialog, Sound_MetaHandler);
  216.     
  217.     // Show the dialog
  218.     ShowWindow(gSoundDialog);
  219.     
  220.     // Initialize the SSpLocalizationData state to garbage
  221.     memset(&gSoundPrev3DInfo, 0x55, sizeof(SSpLocalizationData));
  222. }
  223.  
  224.  
  225. /* =============================================================================
  226.  *        Sound_Exit (external)
  227.  *
  228.  *    Prepares for exit.
  229.  * ========================================================================== */
  230. void Sound_Exit(
  231.     void)
  232. {
  233.     Sound_PlaySilence();
  234.     assert(gSoundResource == NULL);
  235.     
  236.     if (gSoundChannel != NULL)
  237.     {
  238.         SndDisposeChannel(gSoundChannel, true);
  239.         gSoundChannel = NULL;
  240.     }
  241.     
  242.     if (gSoundDialog != NULL)
  243.     {
  244.         DisposeDialog(gSoundDialog);
  245.         gSoundDialog = NULL;
  246.     }
  247. }
  248.  
  249.  
  250. /* =============================================================================
  251.  *        Sound_MetaHandler (internal)
  252.  *
  253.  *    Returns the method function pointer that corresponds to the given ID.
  254.  * ========================================================================== */
  255. WindowMethodPtr Sound_MetaHandler(
  256.     WindowMethod        inMethod)
  257. {
  258.     WindowMethodPtr        result;
  259.     
  260.     result = NULL;
  261.     
  262.     switch (inMethod)
  263.     {
  264.         case kWindowMethod_ConsumeEvent:
  265.             result = (WindowMethodPtr) Sound_ConsumeEvent;
  266.         break;
  267.         
  268.         case kWindowMethod_Update:
  269.             result = (WindowMethodPtr) Sound_Update;
  270.         break;
  271.     }
  272.     
  273.     return result;
  274. }
  275.  
  276.  
  277. /* =============================================================================
  278.  *        Sound_ConsumeEvent (internal)
  279.  *
  280.  *    Called for each event when this is the front window.
  281.  * ========================================================================== */
  282. void Sound_ConsumeEvent(
  283.     WindowPtr            inWindow,
  284.     const EventRecord*    inEvent,
  285.     Boolean*            outConsumed)
  286. {
  287.     #pragma unused (inWindow)
  288.     Boolean                consumed;
  289.     WindowPtr            window;
  290.     short                item;
  291.     
  292.     assert(inEvent != NULL);
  293.     assert(outConsumed != NULL);
  294.     
  295.     consumed = false;
  296.     
  297.     if (inEvent->what == activateEvt)
  298.     {
  299.         // We need to look at the activate event here because it is
  300.         // consumed by IsDialogEvent/DialogSelect below and so never
  301.         // gets to the window stuff
  302.         window = (WindowPtr) inEvent->message;
  303.         
  304.         if (inEvent->modifiers & activeFlag)
  305.         {
  306.             Window_Activate(window);
  307.         }
  308.         else
  309.         {
  310.             Window_Deactivate(window);
  311.         }
  312.     }
  313.         
  314.     // Do dialog stuff
  315.     if (inEvent->what != keyDown || (inEvent->modifiers & cmdKey) == 0)
  316.     {
  317.         consumed = IsDialogEvent(inEvent);
  318.         if (consumed)
  319.         {
  320.             DialogSelect(inEvent, &window, &item);
  321.         }
  322.     }
  323.     
  324.     // Return the result
  325.     *outConsumed = consumed;
  326. }
  327.  
  328.  
  329. /* =============================================================================
  330.  *        Sound_Update (internal)
  331.  *
  332.  *    Updates the contents of the window.
  333.  * ========================================================================== */
  334. void Sound_Update(
  335.     WindowPtr            inWindow)
  336. {
  337.     DrawDialog(inWindow);
  338. }
  339.  
  340.  
  341. /* =============================================================================
  342.  *        Sound_Configure (external)
  343.  *
  344.  *    Stops the current sound, puts up the Configure dialog box, and resumes the
  345.  *    stopped sound.
  346.  * ========================================================================== */
  347. void Sound_Configure(
  348.     void)
  349. {
  350.     OSStatus            err;
  351.     Boolean                playing;
  352.     short                resID;
  353.     ResType                resType;
  354.     Str255                resName;
  355.     
  356.     // Find out which sound to restore
  357.     playing = gSoundResource != NULL;
  358.     
  359.     if (playing)
  360.     {
  361.         GetResInfo((Handle) gSoundResource, &resID, &resType, resName);
  362.     }
  363.     
  364.     // Quiet
  365.     Sound_PlaySilence();
  366.     
  367.     // Configure
  368.     err = SSpConfigureSpeakerSetup(EventProc);
  369.     Message_CheckError(err, "Sound_Configure", "SSpConfigureSpeakerSetup");
  370.     
  371.     // Play it again, Sam
  372.     if (playing)
  373.     {
  374.         Sound_PlayResource(resName);
  375.     }
  376. }
  377.  
  378.  
  379. /* =============================================================================
  380.  *        EventProc (internal)
  381.  *
  382.  *    Called to process events during the 3D sound Configure dialog.  Returns
  383.  *    true if the event was handled (except for update events).
  384.  * ========================================================================== */
  385. Boolean EventProc(
  386.     EventRecord        *inEvent)
  387. {
  388.     WindowPtr                wind;
  389.     
  390.     assert(inEvent != NULL);
  391.     
  392.     if (inEvent->what == updateEvt)
  393.     {
  394.         wind = (WindowPtr) inEvent->message;
  395.         
  396.         if (Window_IsMine(wind))
  397.         {
  398.             SetPort(wind);
  399.             BeginUpdate(wind);
  400.             Window_Update(wind);
  401.             EndUpdate(wind);
  402.         }
  403.     }
  404.     
  405.     return false;
  406. }
  407.  
  408.  
  409. /* =============================================================================
  410.  *        Sound_PlaySilence (external)
  411.  *
  412.  *    Stops any sound that is playing.
  413.  * ========================================================================== */
  414. void Sound_PlaySilence(
  415.     void)
  416. {
  417.     OSStatus            err;
  418.     SndCommand            sndCommand;
  419.     
  420.     sndCommand.cmd = quietCmd;
  421.     sndCommand.param1 = 0;
  422.     sndCommand.param2 = 0;
  423.     err = SndDoImmediate(gSoundChannel, &sndCommand);
  424.     Message_CheckError(err, "Sound_PlaySilence", "SndDoImmediate");
  425.     
  426.     if (gSoundResource != NULL)
  427.     {
  428.         ReleaseResource((Handle) gSoundResource);
  429.         gSoundResource = NULL;
  430.     }
  431. }
  432.  
  433.  
  434. /* =============================================================================
  435.  *        Sound_PlayResource (external)
  436.  *
  437.  *    Plays the 'snd ' resource that has the given name.  Returns true if
  438.  *    successful; returns false if unsuccessful and therefore silence is happening.
  439.  * ========================================================================== */
  440. Boolean Sound_PlayResource(
  441.     Str255                inSndName)
  442. {
  443.     OSStatus            err;
  444.     SndCommand            sndCommand;
  445.     long                offset;
  446.     
  447.     // Silence the sound channel and get rid of the old resource
  448.     Sound_PlaySilence();
  449.     
  450.     // Grab the resource
  451.     gSoundResource = (SndListHandle) GetNamedResource('snd ', inSndName);
  452.     if (gSoundResource == NULL || ResError() != noErr)
  453.     {
  454.         StopAlert(kAlrtID_BadSndLoad, NULL);
  455.         goto bail;
  456.     }
  457.     
  458.     // Lock it down
  459.     HLockHi((Handle) gSoundResource);
  460.     
  461.     // Play it indefinitely
  462.     GetSoundHeaderOffset(gSoundResource, &offset);
  463.     
  464.     sndCommand.cmd = soundCmd;
  465.     sndCommand.param1 = 0;
  466.     sndCommand.param2 = (long) *gSoundResource + offset;
  467.     err = SndDoImmediate(gSoundChannel, &sndCommand);
  468.     Message_CheckError(err, "Sound_PlayResource", "SndDoImmediate");
  469.  
  470.     sndCommand.cmd = freqCmd;
  471.     sndCommand.param1 = 0;
  472.     sndCommand.param2 = 60;
  473.     err = SndDoImmediate(gSoundChannel, &sndCommand);
  474.     Message_CheckError(err, "Sound_PlayResource", "SndDoImmediate");
  475.     
  476.     return true;
  477.  
  478.     // Error exit
  479. bail:
  480.     if (gSoundResource != NULL)
  481.     {
  482.         ReleaseResource((Handle) gSoundResource);
  483.         gSoundResource = NULL;
  484.     }
  485.     
  486.     return false;
  487. }
  488.  
  489.  
  490. /* =============================================================================
  491.  *        Sound_Set3DInfo (external)
  492.  *
  493.  *    Sends the given 3D info to the sound channel.
  494.  * ========================================================================== */
  495. void Sound_Set3DInfo(
  496.     const SSpLocalizationData*    in3DInfo)
  497. {
  498.     OSStatus            err;
  499.     Str255                str;
  500.     UnsignedWide        time;
  501.     
  502.     static UnsignedWide    prevTime = {0, 0};
  503.     
  504.     assert(in3DInfo != NULL);
  505.     
  506.     // Change the filter
  507.     err = SndSetInfo(gSoundChannel, siSSpLocalization, (SSpLocalizationData*) in3DInfo);
  508.     Message_CheckError(err, "Sound_Set3DInfo", "SndSetInfo");
  509.     
  510.     // Update the dialog
  511.     Microseconds(&time);
  512.     
  513.     Utils_SetUInt32Field(
  514.         gSoundDialog,
  515.         kFeedbackItem_Updates,
  516.         1000000.0 / (time.lo-prevTime.lo),
  517.         true);
  518.     
  519.     prevTime = time;
  520.     
  521.     if (gSoundPrev3DInfo.cpuLoad != in3DInfo->cpuLoad)
  522.     {
  523.         Utils_SetUInt32Field(
  524.             gSoundDialog,
  525.             kFeedbackItem_CPULoad,
  526.             in3DInfo->cpuLoad,
  527.             true);
  528.         
  529.         gSoundPrev3DInfo.cpuLoad = in3DInfo->cpuLoad;
  530.     }
  531.     
  532.     if (gSoundPrev3DInfo.medium != in3DInfo->medium)
  533.     {
  534.         switch (in3DInfo->medium)
  535.         {
  536.             case kSSpMedium_Air:
  537.                 strcpy((char*) str, (char*) "\pkSSp…Air");
  538.             break;
  539.             
  540.             case kSSpMedium_Water:
  541.                 strcpy((char*) str, (char*) "\pkSSp…Water");
  542.             break;
  543.             
  544.             default:
  545.                 sprintf((char*) str, "x<<%lu>>", (unsigned long) in3DInfo->medium);
  546.                 str[0] = strlen((char*) str) - 1;
  547.         }
  548.         
  549.         Utils_SetStr255Field(
  550.             gSoundDialog,
  551.             kFeedbackItem_Medium,
  552.             str,
  553.             true);
  554.         
  555.         gSoundPrev3DInfo.medium = in3DInfo->medium;
  556.     }
  557.     
  558.     if (gSoundPrev3DInfo.humidity != in3DInfo->humidity)
  559.     {
  560.         Utils_SetFloatField(
  561.             gSoundDialog,
  562.             kFeedbackItem_Humidity,
  563.             in3DInfo->humidity,
  564.             true);
  565.         
  566.         gSoundPrev3DInfo.humidity = in3DInfo->humidity;
  567.     }
  568.     
  569.     if (gSoundPrev3DInfo.roomSize != in3DInfo->roomSize)
  570.     {
  571.         Utils_SetFloatField(
  572.             gSoundDialog,
  573.             kFeedbackItem_RoomSize,
  574.             in3DInfo->roomSize,
  575.             true);
  576.         
  577.         gSoundPrev3DInfo.roomSize = in3DInfo->roomSize;
  578.     }
  579.     
  580.     if (gSoundPrev3DInfo.roomReflectivity != in3DInfo->roomReflectivity)
  581.     {
  582.         Utils_SetFloatField(
  583.             gSoundDialog,
  584.             kFeedbackItem_RoomReflectivity,
  585.             in3DInfo->roomReflectivity,
  586.             true);
  587.         
  588.         gSoundPrev3DInfo.roomReflectivity = in3DInfo->roomReflectivity;
  589.     }
  590.     
  591.     if (gSoundPrev3DInfo.reverbAttenuation != in3DInfo->reverbAttenuation)
  592.     {
  593.         Utils_SetFloatField(
  594.             gSoundDialog,
  595.             kFeedbackItem_ReverbAttenuation,
  596.             in3DInfo->reverbAttenuation,
  597.             true);
  598.         
  599.         gSoundPrev3DInfo.reverbAttenuation = in3DInfo->reverbAttenuation;
  600.     }
  601.     
  602.     if (gSoundPrev3DInfo.sourceMode != in3DInfo->sourceMode)
  603.     {
  604.         switch (in3DInfo->sourceMode)
  605.         {
  606.             case kSSpSourceMode_Unfiltered:
  607.                 strcpy((char*) str, (char*) "\pkSSp…Unfiltered");
  608.             break;
  609.             
  610.             case kSSpSourceMode_Localized:
  611.                 strcpy((char*) str, (char*) "\pkSSp…Localized");
  612.             break;
  613.             
  614.             case kSSpSourceMode_Ambient:
  615.                 strcpy((char*) str, (char*) "\pkSSp…Ambient");
  616.             break;
  617.             
  618.             case kSSpSourceMode_Binaural:
  619.                 strcpy((char*) str, (char*) "\pkSSp…Binaural");
  620.             break;
  621.             
  622.             default:
  623.                 sprintf((char*) str, "x<<%lu>>", (unsigned long) in3DInfo->sourceMode);
  624.                 str[0] = strlen((char*) str) - 1;
  625.         }
  626.         
  627.         Utils_SetStr255Field(
  628.             gSoundDialog,
  629.             kFeedbackItem_SourceMode,
  630.             str,
  631.             true);
  632.         
  633.         gSoundPrev3DInfo.sourceMode = in3DInfo->sourceMode;
  634.     }
  635.     
  636.     if (gSoundPrev3DInfo.referenceDistance != in3DInfo->referenceDistance)
  637.     {
  638.         Utils_SetFloatField(
  639.             gSoundDialog,
  640.             kFeedbackItem_ReferenceDistance,
  641.             in3DInfo->referenceDistance,
  642.             true);
  643.         
  644.         gSoundPrev3DInfo.referenceDistance = in3DInfo->referenceDistance;
  645.     }
  646.     
  647.     if (gSoundPrev3DInfo.coneAngleCos != in3DInfo->coneAngleCos)
  648.     {
  649.         Utils_SetFloatField(
  650.             gSoundDialog,
  651.             kFeedbackItem_ConeAngleCos,
  652.             in3DInfo->coneAngleCos,
  653.             true);
  654.         
  655.         gSoundPrev3DInfo.coneAngleCos = in3DInfo->coneAngleCos;
  656.     }
  657.     
  658.     if (gSoundPrev3DInfo.coneAttenuation != in3DInfo->coneAttenuation)
  659.     {
  660.         Utils_SetFloatField(
  661.             gSoundDialog,
  662.             kFeedbackItem_ConeAttenuation,
  663.             in3DInfo->coneAttenuation,
  664.             true);
  665.         
  666.         gSoundPrev3DInfo.coneAttenuation = in3DInfo->coneAttenuation;
  667.     }
  668.     
  669.     if (gSoundPrev3DInfo.currentLocation.elevation != in3DInfo->currentLocation.elevation)
  670.     {
  671.         Utils_SetFloatField(
  672.             gSoundDialog,
  673.             kFeedbackItem_Elevation,
  674.             in3DInfo->currentLocation.elevation,
  675.             true);
  676.         
  677.         gSoundPrev3DInfo.currentLocation.elevation = in3DInfo->currentLocation.elevation;
  678.     }
  679.     
  680.     if (gSoundPrev3DInfo.currentLocation.azimuth != in3DInfo->currentLocation.azimuth)
  681.     {
  682.         Utils_SetFloatField(
  683.             gSoundDialog,
  684.             kFeedbackItem_Azimuth,
  685.             in3DInfo->currentLocation.azimuth,
  686.             true);
  687.         
  688.         gSoundPrev3DInfo.currentLocation.azimuth = in3DInfo->currentLocation.azimuth;
  689.     }
  690.     
  691.     if (gSoundPrev3DInfo.currentLocation.distance != in3DInfo->currentLocation.distance)
  692.     {
  693.         Utils_SetFloatField(
  694.             gSoundDialog,
  695.             kFeedbackItem_Distance,
  696.             in3DInfo->currentLocation.distance,
  697.             true);
  698.         
  699.         gSoundPrev3DInfo.currentLocation.distance = in3DInfo->currentLocation.distance;
  700.     }
  701.     
  702.     if (gSoundPrev3DInfo.currentLocation.projectionAngle != in3DInfo->currentLocation.projectionAngle)
  703.     {
  704.         Utils_SetFloatField(
  705.             gSoundDialog,
  706.             kFeedbackItem_ProjectionAngle,
  707.             in3DInfo->currentLocation.projectionAngle,
  708.             true);
  709.         
  710.         gSoundPrev3DInfo.currentLocation.projectionAngle = in3DInfo->currentLocation.projectionAngle;
  711.     }
  712.     
  713.     if (gSoundPrev3DInfo.currentLocation.sourceVelocity != in3DInfo->currentLocation.sourceVelocity)
  714.     {
  715.         Utils_SetFloatField(
  716.             gSoundDialog,
  717.             kFeedbackItem_SourceVelocity,
  718.             in3DInfo->currentLocation.sourceVelocity,
  719.             true);
  720.         
  721.         gSoundPrev3DInfo.currentLocation.sourceVelocity = in3DInfo->currentLocation.sourceVelocity;
  722.     }
  723.     
  724.     if (gSoundPrev3DInfo.currentLocation.listenerVelocity != in3DInfo->currentLocation.listenerVelocity)
  725.     {
  726.         Utils_SetFloatField(
  727.             gSoundDialog,
  728.             kFeedbackItem_ListenerVelocity,
  729.             in3DInfo->currentLocation.listenerVelocity,
  730.             true);
  731.         
  732.         gSoundPrev3DInfo.currentLocation.listenerVelocity = in3DInfo->currentLocation.listenerVelocity;
  733.     }
  734.     
  735.     if (gSoundPrev3DInfo.reserved0 != in3DInfo->reserved0)
  736.     {
  737.         Utils_SetFloatField(
  738.             gSoundDialog,
  739.             kFeedbackItem_Reserved0,
  740.             in3DInfo->reserved0,
  741.             true);
  742.         
  743.         gSoundPrev3DInfo.reserved0 = in3DInfo->reserved0;
  744.     }
  745.     
  746.     if (gSoundPrev3DInfo.reserved1 != in3DInfo->reserved1)
  747.     {
  748.         Utils_SetFloatField(
  749.             gSoundDialog,
  750.             kFeedbackItem_Reserved1,
  751.             in3DInfo->reserved1,
  752.             true);
  753.         
  754.         gSoundPrev3DInfo.reserved1 = in3DInfo->reserved1;
  755.     }
  756.     
  757.     if (gSoundPrev3DInfo.reserved2 != in3DInfo->reserved2)
  758.     {
  759.         Utils_SetFloatField(
  760.             gSoundDialog,
  761.             kFeedbackItem_Reserved2,
  762.             in3DInfo->reserved2,
  763.             true);
  764.         
  765.         gSoundPrev3DInfo.reserved2 = in3DInfo->reserved2;
  766.     }
  767.     
  768.     if (gSoundPrev3DInfo.reserved3 != in3DInfo->reserved3)
  769.     {
  770.         Utils_SetFloatField(
  771.             gSoundDialog,
  772.             kFeedbackItem_Reserved3,
  773.             in3DInfo->reserved3,
  774.             true);
  775.         
  776.         gSoundPrev3DInfo.reserved3 = in3DInfo->reserved3;
  777.     }
  778.     
  779.     if (gSoundPrev3DInfo.virtualSourceCount != in3DInfo->virtualSourceCount)
  780.     {
  781.         Utils_SetFloatField(
  782.             gSoundDialog,
  783.             kFeedbackItem_VirtualSourceCount,
  784.             in3DInfo->virtualSourceCount,
  785.             true);
  786.         
  787.         gSoundPrev3DInfo.virtualSourceCount = in3DInfo->virtualSourceCount;
  788.     }
  789. }
  790.  
  791.  
  792.